﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace Ezviz.OpenSDK
{
   
    /// <summary>
    /// 会话对象
    /// </summary>
    public class OpenSDKSession:IDisposable
    {
        /// <summary>
        /// 消息处理器
        /// </summary>
        internal static readonly MessageHandler MessageHandler;

        static OpenSDKSession()
        {
            OpenSDKSession.MessageHandler = new MessageHandler(OpenSDKSession.HandleMessage);
        }
        /// <summary>
        /// 消息接收事件
        /// </summary>
        public event EventHandler<SessionMessageEventArgs> MessageReceived;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="sdk"></param>
        internal OpenSDKSession( bool sync)
        {
        }
      
        /// <summary>
        /// 内部维持的会话对象
        /// </summary>
        internal IntPtr Session
        {
            get;
            set;
        } 

        public bool IsDisposed
        {
            get
            {
                return this.Session == IntPtr.Zero;
            }
        }

        /// <summary>
        /// 异步模式
        /// </summary>
        public bool Sync
        {
            get;
        }

        /// <summary>
        /// 播放视频
        /// </summary>
        /// <param name="hwnd">播放窗口句柄</param>
        /// <param name="cameraId">监控点ID</param>
        /// <param name="accessToken">认证token</param>
        /// <param name="videoLevel">视频质量，输入范围在0-2之间</param>
        /// <param name="safeKey">视频加密密钥，默认为设备验证码，无设备验证码则为ABCDEF</param>
        /// <param name="nSCBMsg">同步回调传出参数,如果为同步，不允许为NULL </param>
        /// <returns>0表示成功，非0表示失败 </returns>
        public  int StartRealPlay(IntPtr hwnd, string cameraId, string accessToken, VideoLevel videoLevel,NSCBMsg nSCBMsg = null, string safeKey = "ABCDEF")
        {
           return OpenNetStream.OpenSDK_StartRealPlay(this.Session, hwnd, cameraId, accessToken, videoLevel, safeKey, OpenSDK.AppKey,ref nSCBMsg);
        }

        /// <summary>
        /// 设置数据回调 
        /// </summary>
        /// <param name="callback">回调函数 </param>
        /// <param name="userData">用户自定义数据，会通过DataCallBack原样抛出 </param>
        /// <returns></returns>
        public int SetDataCallBack(DataCallBack callback,IntPtr userData)
        {
            return OpenNetStream.OpenSDK_SetDataCallBack(this.Session, callback, userData);
        }

        /// <summary>
        ///  停止预览
        /// </summary>
        /// <param name="nSCBMsg"> 同步回调传出参数,如果为同步，不允许为NULL</param>
        /// <returns>0表示成功，非0表示失败 </returns>
        public int StopRealPlay(NSCBMsg nSCBMsg = null)
        {
            return OpenNetStream.OpenSDK_StopRealPlay(this.Session,ref nSCBMsg);
        }

        /// <summary>
        /// 回放
        /// </summary>
        /// <param name="hwnd">播放窗口句柄</param>
        /// <param name="cameraId">监控点ID</param>
        /// <param name="accessToken">认证Token</param>
        /// <param name="safeKey">视频加密密钥</param>
        /// <param name="startTime">开始时间</param>
        /// <param name="stopTime">停止时间</param>
        /// <param name="nSCBMsg">同步回调传出参数,如果为同步，不允许为NULL</param>
        /// <returns>0表示成功，非0表示失败 </returns>
        public int StartPlayBack(IntPtr hwnd, string cameraId, string accessToken, DateTime startTime, DateTime endTime, string safeKey = "ABCDEF", NSCBMsg nSCBMsg = null)
        {
            return OpenNetStream.OpenSDK_StartPlayBack(this.Session, hwnd, cameraId, accessToken, safeKey, startTime.ToString("yyyy-MM-dd hh:mm:ss"), endTime.ToString("yyyy-MM-dd hh:mm:ss"), OpenSDK.AppKey, nSCBMsg);
        }

        /// <summary>
        /// 暂停回放
        /// </summary>
        /// <returns>0表示成功，非0表示失败 </returns>
        /// <remarks>该接口只能在OpenSDK_StartPlayBack() 调用之后才能调用</remarks>
        public int PlayBackPause()
        {
            return OpenNetStream.OpenSDK_PlayBackPause(this.Session);
        }

        /// <summary>
        /// 恢复回放
        /// </summary>
        /// <returns>0表示成功，非0表示失败 </returns>
        /// <remarks>该接口只能在OpenSDK_StartPlayBack()调用之后才能调用 </remarks>
        public int PlayBackResume()
        {
            return OpenNetStream.OpenSDK_PlayBackResume(this.Session);
        }

        /// <summary>
        /// 停止回放
        /// </summary>
        /// <param name="nSCBMsg">同步回调传出参数,如果为同步，不允许为NULL</param>
        /// <returns>0表示成功，非0表示失败 </returns>
        public int StopPlayBack(NSCBMsg nSCBMsg = null)
        {
            return OpenNetStream.OpenSDK_StopPlayBack(this.Session, nSCBMsg);
        }

        /// <summary>
        ///  打开声音
        /// </summary>
        /// <returns> 0表示成功，-1表示失败<see cref="OpenSDKErrorCode"/></returns>
        public int OpenSound()
        {
            return OpenNetStream.OpenSDK_OpenSound(this.Session);
        }

        /// <summary>
        ///  关闭声音
        /// </summary>
        /// <returns> 0表示成功，-1表示失败<see cref="OpenSDKErrorCode"/></returns>
        public int CloseSound()
        {
            return OpenNetStream.OpenSDK_CloseSound(this.Session);
        }

        /// <summary>
        ///截屏，StartRealPlay成功情况下使用 
        /// </summary>
        /// <param name="filename">图片保存路径，格式为JPG，支持中文，UTF-8格式</param>
        /// <returns>0表示成功，-1表示失败 </returns>
        public int CapturePicture(string filename)
        {
            return OpenNetStream.OpenSDK_CapturePicture(this.Session,filename);
        }
        /// <summary>
        ///   获取音量
        /// </summary>
        /// <returns> 音量大小，0-100之间</returns>
        public ushort GetVolume()
        {
            return OpenNetStream.OpenSDK_GetVolume(this.Session);
        }
        /// <summary>
        ///  设置音量
        /// </summary>
        /// <param name="volume">音量大小，0-100之间</param>
        /// <returns> 0表示成功，-1表示失败<see cref="OpenSDKErrorCode"/> </returns>
        public int SetVolume(ushort volume)
        {
            return OpenNetStream.OpenSDK_SetVolume(this.Session, volume);
        }

        public DateTime GetOSDTime()
        {
            STREAM_TIME time=new STREAM_TIME();
            int result=OpenNetStream.OpenSDK_GetOSDTime(this.Session, ref time);
            return DateTime.Now;
        }

        /// <summary>
        /// 开启语音对讲, 不支持多个设备同时对接
        /// </summary>
        /// <param name="session">会话</param>
        /// <param name="accessToken">认证Token</param>
        /// <param name="cameraId">摄像头Id</param>
        /// <returns>0表示成功，-1表示失败， -2表示对讲已经开启 </returns>
        public int StartVoiceTalk(string accessToken, string cameraId)
        {
            return OpenNetStream.OpenSDK_StartVoiceTalk(this.Session,accessToken, cameraId);
        }
        /// <summary>
        /// 结束语音对讲
        /// </summary>
        /// <returns>0表示成功，-1表示失败<see cref="OpenSDKErrorCode"/></returns>
        public int StopVoiceTalk()
        {
            return OpenNetStream.OpenSDK_StopVoiceTalk(this.Session);
        }

        /// <summary>
        /// 云台控制
        /// </summary>
        /// <param name="accessToken">认证Token</param>
        /// <param name="cameraId">监控点Id</param>
        /// <param name="command">云台控制命令</param>
        /// <param name="action">云台操作命令</param>
        /// <param name="speed">速度0-7之间</param>
        /// <param name="nSCBMsg"> 同步回调传出参数,如果为同步，不允许为NULL</param>
        /// <returns>0表示成功，-1表示失败<see cref="OpenSDKErrorCode"/></returns>
        public int PTZCtrl(string accessToken, string cameraId, PTZCommand command, PTZAction action, int speed, NSCBMsg nSCBMsg = null)
        {
            return OpenNetStream.OpenSDK_PTZCtrl(this.Session, accessToken, cameraId, command, action, speed, nSCBMsg) ;
        }

        /// <summary>
        /// 按监控点ID进行布撤防
        /// </summary>
        /// <param name="session">会话</param>
        /// <param name="accessToken">认证Token</param>
        /// <param name="cameraId">监控点Id</param>
        /// <param name="type">布撤防类型</param>
        /// <param name="status">布撤防状态</param>
        /// <param name="actor">布撤防设备类型</param>
        /// <param name="nSCBMsg">同步回调传出参数,如果为同步，不允许为NULL</param>
        /// <returns>非负表示成功，-1表示失败 </returns>
        public int DevDefence(string accessToken, string cameraId, EZDefenceType type, EZDefenceStatus status, EZDefenceActor actor, NSCBMsg nSCBMsg = null)
        {
            return OpenNetStream.OpenSDK_DevDefence(this.Session, accessToken, cameraId, type, status, actor, nSCBMsg);
        }

        /// <summary>
        /// 按设备ID和通道号进行布撤防
        /// </summary>
        /// <param name="accessToken">认证Token</param>
        /// <param name="deviceId">设备Id</param>
        /// <param name="cameraNo">通道号，操作设备本身通道号为0</param>
        /// <param name="type">布撤防类型</param>
        /// <param name="status">布撤防状态</param>
        /// <param name="actor">布撤防设备类型</param>
        /// <param name="nSCBMsg"> 同步回调传出参数,如果为同步，不允许为NULL</param>
        /// <returns>非负表示成功，-1表示失败 </returns>
        public int DevDefenceByDev(string accessToken, string deviceId, int cameraNo, EZDefenceType type, EZDefenceStatus status, EZDefenceActor actor, NSCBMsg nSCBMsg = null)
        {
            return OpenNetStream.OpenSDK_DevDefenceByDev(this.Session, accessToken, deviceId,cameraNo, type, status, actor, nSCBMsg);
        }

        /// <summary>
        /// 处理消息
        /// </summary>
        /// <param name="ptr"></param>
        /// <param name="msgType"></param>
        /// <param name="errorCode"></param>
        /// <param name="errorMessage"></param>
        /// <param name="userData"></param>
        private static void HandleMessage(IntPtr ptr, EZMessageType msgType, uint errorCode, string errorMessage, IntPtr userData)
        {
            int value = Marshal.ReadInt32(ptr);
            OpenSDKSession session;
            if (!OpenSDK.SESSIONS.TryGetValue(value, out session))
                return;
            if (session != null)
                //处理事件，触发事件
                session.OnMessageReceived(msgType, Convert.ToInt32(errorCode), errorMessage, userData);
        }

        /// <summary>
        /// 关闭会话
        /// </summary>
        public void Close()
        {
            if (this.IsDisposed)
                return;
            //释放会话
            int result = OpenNetStream.OpenSDK_FreeSession(this.Session);
            if (result != OpenSDKErrorCode.OK)
                return;
            OpenSDK.SESSIONS.Remove(Marshal.ReadInt32(this.Session));
            this.Session = IntPtr.Zero;
        }
     
        //触发消息接收事件
        private void OnMessageReceived(EZMessageType msgType, int errorCode, string errorMessage, IntPtr userData)
        {
            this.MessageReceived?.Invoke(this, new SessionMessageEventArgs(this,msgType, errorCode, errorMessage, userData));
        }

        public void Dispose()
        {
            if (this.IsDisposed)
                return;
            this.Close();
        }
    }
}
